#include "../userprog/syscall.h"

/*/======== Ticket Clerk Function ========*/
void main()
{
int myIndex;


/*Shared Data*/
int latestIndexLock;
int latestIndex;
int latestIndexCondition;
int tcStateLock;
int CLERK_AVAILABLE;
int CLERK_BUSY;
int tcInteractionCondition;
int tcInteractionLock;
int CLERK_ON_BREAK;
int tcState;
int PRINT_DEBUG_MESSAGES;
int PRINT_OUTPUT_MESSAGES;
int NUM_TICKET_CLERKS;
int numTicketsDesired;
int TICKET_PRICE;
int profitLock;
int totalTicketsSold;
int tcBreakStopLock;
int tcBreakLock;
int tcBreakStopCondition;
int tcBreakCondition;
int tcLineManager;
int tcLineLength;
int tcLineCondition;

/*Acquire Shared Data*/
NUM_TICKET_CLERKS = CreateMV(1,"NUM_TICKET_CLERKS", 17);
latestIndexLock = CreateLock("latestIndexLock", 15);
latestIndex = CreateMV(1,"latestIndex",11);
latestIndexCondition = CreateCondition("latestIndexCondition",20);
tcStateLock = CreateMV(GetMV(NUM_TICKET_CLERKS,0), "tcStateLock", 11);
CLERK_AVAILABLE = CreateMV(1,"CLERK_AVAILABLE",15);
tcInteractionCondition = CreateMV(GetMV(NUM_TICKET_CLERKS,0), "tcInteractionCondition", 22);
tcInteractionLock = CreateMV(GetMV(NUM_TICKET_CLERKS,0), "tcInteractionLock", 17);
CLERK_ON_BREAK = CreateMV(1,"CLERK_ON_BREAK",14);
tcState = CreateMV(GetMV(NUM_TICKET_CLERKS,0), "tcState", 7);
PRINT_DEBUG_MESSAGES = CreateMV(1,"PRINT_DEBUG_MESSAGES",20);
PRINT_OUTPUT_MESSAGES = CreateMV(1,"PRINT_OUTPUT_MESSAGES",21);
numTicketsDesired = CreateMV(GetMV(NUM_TICKET_CLERKS,0), "numTicketsDesired",17);
TICKET_PRICE = CreateMV(1, "TICKET_PRICE", 12);
profitLock = CreateLock("profitLock",10);
totalTicketsSold = CreateMV(GetMV(NUM_TICKET_CLERKS,0),"totalTicketsSold", 16);
tcBreakStopLock = CreateMV(GetMV(NUM_TICKET_CLERKS,0),"tcBreakStopLock",15);
tcBreakLock = CreateMV(GetMV(NUM_TICKET_CLERKS,0),"tcBreakLock",11);
tcBreakStopCondition = CreateMV(GetMV(NUM_TICKET_CLERKS,0), "tcBreakStopCondition",20);
tcBreakCondition = CreateMV(GetMV(NUM_TICKET_CLERKS,0), "tcBreakCondition",16);
tcLineManager = CreateLock("tcLineManager",13);
tcLineLength = CreateMV(GetMV(NUM_TICKET_CLERKS,0),"tcLineLength",12);
CLERK_BUSY = CreateMV(1,"CLERK_BUSY",10);
tcLineCondition = CreateMV(GetMV(NUM_TICKET_CLERKS,0),"tcLineCondition",15);

	AcquireLock(latestIndexLock);
	myIndex = GetMV(latestIndex,0);
	SignalCondition(latestIndexCondition, latestIndexLock);
	ReleaseLock(latestIndexLock);


	if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: created\n", 25, 1, myIndex);
	AcquireLock(GetMV(tcStateLock,myIndex));
	SetMV(tcState,myIndex, GetMV(CLERK_AVAILABLE,0));
	
	while(1)
	{
		/*/Wait for Customer's ticket order*/
		tcInteractionWaitLabel:
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: waiting for next Customer\n", 43, 1, myIndex);
		WaitCondition(GetMV(tcInteractionCondition,myIndex), GetMV(tcInteractionLock,myIndex));
		
		if(GetMV(tcState,myIndex) == GetMV(CLERK_ON_BREAK,0))
		{
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: going on break...\n", 35, 1, myIndex);
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: acquiring tcBreakLock %d\n", 42, 2, myIndex*100 + myIndex);
			AcquireLock(GetMV(tcBreakLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: signalling tcInteractionLock %d\n", 49, 2, myIndex*100 + myIndex);
			SignalCondition(GetMV(tcInteractionCondition,myIndex), GetMV(tcInteractionLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: releasing tcInteractionLock %d\n", 48, 2, myIndex*100 + myIndex);
			ReleaseLock(GetMV(tcInteractionLock,myIndex));
			goto tcBreakLabel;
		}
		
		/*/After getting signalled by Customer with ticket order*/
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: acquiring tcInteractionLock %d\n", 48, 2, myIndex*100 + myIndex);
		AcquireLock(GetMV(tcInteractionLock,myIndex));
		
		SetMV(tcState,myIndex,GetMV(CLERK_BUSY,0));
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: processing ticket order of size %d\n", 52, 2, myIndex*100 + GetMV(numTicketsDesired,myIndex));
		if(GetMV(PRINT_OUTPUT_MESSAGES,0)) FPrint("TicketClerk %d has an order for %d and the cost is %d.\n", 56, 3, 
			myIndex*10000 + GetMV(numTicketsDesired,myIndex)*100 + GetMV(numTicketsDesired,myIndex) * GetMV(TICKET_PRICE,0));
		
		/*/Process ticket order and add to total*/
		AcquireLock(profitLock);
		SetMV(totalTicketsSold,myIndex, GetMV(totalTicketsSold,myIndex) + GetMV(numTicketsDesired,myIndex));
		ReleaseLock(profitLock);
		
		/*/Signal Customer to complete transaction		*/
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: signalling Customer with completed order of size %d\n", 69, 2, myIndex*100 + GetMV(numTicketsDesired,myIndex));
		SignalCondition(GetMV(tcInteractionCondition,myIndex), GetMV(tcInteractionLock,myIndex));
		
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: waiting for Customer to receive tickets\n", 57, 1, myIndex);
		WaitCondition(GetMV(tcInteractionCondition,myIndex), GetMV(tcInteractionLock,myIndex));
		
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: Customer received tickets succesfully\n", 55, 1, myIndex);
		
		/*/Release state for manager to edit*/
		ReleaseLock(GetMV(tcStateLock,myIndex));
		
		/*/Finished dealing with customer, perhaps go on break*/
		AcquireLock(GetMV(tcStateLock,myIndex));
		if(GetMV(tcState,myIndex) == GetMV(CLERK_ON_BREAK,0))
		{
			if(GetMV(PRINT_OUTPUT_MESSAGES,0)) FPrint("TicketClerk %d is going on break.\n", 35, 1, myIndex);
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: signalling Manager that I am going on break\n", 61, 1, myIndex);
			
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: acquiring tcBreakStopLock %d\n", 46, 2, myIndex*100 + myIndex);
			AcquireLock(GetMV(tcBreakStopLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: acquiring tcBreakLock %d\n", 42, 2, myIndex*100 + myIndex);
			AcquireLock(GetMV(tcBreakLock,myIndex));
			
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: signalling tcBreakStopLock %d\n", 47, 2, myIndex*100 + myIndex);
			SignalCondition(GetMV(tcBreakStopCondition,myIndex), GetMV(tcBreakStopLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: releasing tcBreakStopLock %d\n", 46, 2, myIndex*100 + myIndex);
			ReleaseLock(GetMV(tcBreakStopLock,myIndex));
			
			tcBreakLabel:
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: releasing tcStateLock %d\n", 42, 2, myIndex*100 + myIndex);
			ReleaseLock(GetMV(tcStateLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: waiting tcBreakLock %d\n", 40, 2, myIndex*100 + myIndex);
			WaitCondition(GetMV(tcBreakCondition,myIndex), GetMV(tcBreakLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: acquiring tcStateLock %d\n", 42, 2, myIndex*100 + myIndex);
			AcquireLock(GetMV(tcStateLock,myIndex));
			
			if(GetMV(PRINT_OUTPUT_MESSAGES,0)) FPrint("TicketClerk %d is coming off break.\n", 37, 1, myIndex);
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: returning from break\n", 38, 1, myIndex);
			
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: acquiring tcInteractionLock %d\n", 48, 2, myIndex*100 + myIndex);
			AcquireLock(GetMV(tcInteractionLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: signalling tcBreakLock %d\n", 43, 2, myIndex*100 + myIndex);
			SignalCondition(GetMV(tcBreakCondition,myIndex), GetMV(tcBreakLock,myIndex));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: releasing tcBreakLock %d\n", 42, 2, myIndex*100 + myIndex);
			ReleaseLock(GetMV(tcBreakLock,myIndex));
			goto tcInteractionWaitLabel;
		}
		
		/*/Lock down lines before accepting next Customer*/
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: acquiring Lock for Customer search\n", 52, 1, myIndex);
		AcquireLock(tcLineManager);
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: acquiring tcInteractionLock %d\n", 48, 1, myIndex*100 + myIndex);
		AcquireLock(GetMV(tcInteractionLock,myIndex));
		
		/*/Check for customers in line*/
		if(GetMV(tcLineLength,myIndex) > 0)
		{
			/*/I have a customer in line, set myself to busy and decrement line length*/
			if(GetMV(PRINT_OUTPUT_MESSAGES,0)) FPrint("TicketClerk %d has a line length %d and is signalling a customer.\n", 67, 2, myIndex*100 + GetMV(tcLineLength,myIndex));
			
			SetMV(tcState,myIndex, CLERK_BUSY);
			SetMV(tcLineLength,myIndex, GetMV(tcLineLength,myIndex) - 1);
			
			/*/Wake up 1 customer*/
			SignalCondition(GetMV(tcLineCondition,myIndex), tcLineManager);
			
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: woke up next Customer\n", 39, 1, myIndex);
		}
		else
		{
			/*/No one in my line, set myself to available*/
			SetMV(tcState,myIndex, GetMV(CLERK_AVAILABLE,0));
			if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: no Customers in line\n", 38, 1, myIndex);
			if(GetMV(PRINT_OUTPUT_MESSAGES,0)) FPrint("TicketClerk %d has no one in line.  I am available for a customer.\n", 68, 1, myIndex);
		}
		
		/*/Release and allow other Customers to search lines*/
		if(GetMV(PRINT_DEBUG_MESSAGES,0)) FPrint("TicketClerk %d: releasing Lock for Customer search\n", 52, 1, myIndex);
		ReleaseLock(tcLineManager);
	}
	/* 
	Exit(0);
	*/
}